#include "stm32f4xx.h"                  // Device header
#include "stm32f4xx_conf.h"
#include "CRC.h"

/*
 *函数简介:CRC结构体初始化
 *参数说明:CRC结构体
 *参数说明:CRC类型
 *返回类型:无
 *备注:只能初始化特定18种CRC类型,宽度有8、16和32位
 */
void CRC_StructureInit(CRC_CRCTypeDef *CRC_Structure,CRCCRCType_TypeDef CRC_Type)
{
	if(CRC_Type>=0 && CRC_Type<=3)CRC_Structure->Width=8;
	if(CRC_Type>=4 && CRC_Type<=13)CRC_Structure->Width=16;
	if(CRC_Type>=14 && CRC_Type<=17)CRC_Structure->Width=32;//初始化宽度
	
	if(CRC_Type==CRC_8 || CRC_Type==CRC_8_ITU ||  CRC_Type==CRC_16_CCITT_FALSE || CRC_Type==CRC_16_XMODEM || CRC_Type==CRC_32_MPEG_2)CRC_Structure->IOTurn=0;
	else CRC_Structure->IOTurn=1;//初始化输入输出反转
	
	switch((uint8_t)CRC_Type)//初始化多项式、初始值和结果异或值
	{
		case CRC_8:CRC_Structure->Poly=0x107;CRC_Structure->Initial=0x00;CRC_Structure->OUTXOR=0x00;break;
		case CRC_8_ITU:CRC_Structure->Poly=0x107;CRC_Structure->Initial=0x00;CRC_Structure->OUTXOR=0x55;break;
		case CRC_8_ROHC:CRC_Structure->Poly=0x107;CRC_Structure->Initial=0xFF;CRC_Structure->OUTXOR=0x00;break;
		case CRC_8_MAXIM:CRC_Structure->Poly=0x131;CRC_Structure->Initial=0x00;CRC_Structure->OUTXOR=0x00;break;
		case CRC_16_IBM:CRC_Structure->Poly=0x18005;CRC_Structure->Initial=0x0000;CRC_Structure->OUTXOR=0x0000;break;
		case CRC_16_MAXIM:CRC_Structure->Poly=0x18005;CRC_Structure->Initial=0x0000;CRC_Structure->OUTXOR=0xFFFF;break;
		case CRC_16_USB:CRC_Structure->Poly=0x18005;CRC_Structure->Initial=0xFFFF;CRC_Structure->OUTXOR=0xFFFF;break;
		case CRC_16_MODBUS:CRC_Structure->Poly=0x18005;CRC_Structure->Initial=0xFFFF;CRC_Structure->OUTXOR=0x0000;break;
		case CRC_16_CCITT:CRC_Structure->Poly=0x11021;CRC_Structure->Initial=0x0000;CRC_Structure->OUTXOR=0x0000;break;
		case CRC_16_CCITT_FALSE:CRC_Structure->Poly=0x11021;CRC_Structure->Initial=0xFFFF;CRC_Structure->OUTXOR=0x0000;break;
		case CRC_16_X25:CRC_Structure->Poly=0x11021;CRC_Structure->Initial=0xFFFF;CRC_Structure->OUTXOR=0xFFFF;break;
		case CRC_16_XMODEM:CRC_Structure->Poly=0x11021;CRC_Structure->Initial=0x0000;CRC_Structure->OUTXOR=0x0000;break;
		case CRC_16_XMODEM2:CRC_Structure->Poly=0x18408;CRC_Structure->Initial=0x0000;CRC_Structure->OUTXOR=0x0000;break;
		case CRC_16_DNP:CRC_Structure->Poly=0x13D65;CRC_Structure->Initial=0x0000;CRC_Structure->OUTXOR=0xFFFF;break;
		case CRC_32:CRC_Structure->Poly=0x104C11DB7;CRC_Structure->Initial=0xFFFFFFFF;CRC_Structure->OUTXOR=0xFFFFFFFF;break;
		case CRC_32_C:CRC_Structure->Poly=0x11EDC6F41;CRC_Structure->Initial=0xFFFFFFFF;CRC_Structure->OUTXOR=0xFFFFFFFF;break;
		case CRC_32_KOOPMAN:CRC_Structure->Poly=0x1741B8CD7;CRC_Structure->Initial=0xFFFFFFFF;CRC_Structure->OUTXOR=0xFFFFFFFF;break;
		case CRC_32_MPEG_2:CRC_Structure->Poly=0x104C11DB7;CRC_Structure->Initial=0xFFFFFFFF;CRC_Structure->OUTXOR=0x00000000;break;
	}
}

/*
 *函数简介:CRC结构体自定义初始化
 *参数说明:CRC结构体
 *参数说明:CRC宽度
 *参数说明:CRC多项式,长度比宽度大1
 *参数说明:CRC输入输出是否反转,0-不反转,1-反转
 *参数说明:CRC初始值,长度等于宽度
 *参数说明:CRC结果异或值,长度等于宽度
 *返回类型:无
 *备注:宽度在8~32位之间经过测试,其他位数未测试过
 */
void CRC_StructureCustomInit(CRC_CRCTypeDef *CRC_Structure,uint8_t Width,uint64_t Poly,uint8_t IOTurn,uint64_t Initial,uint64_t OUTXOR)
{
	CRC_Structure->Width=Width;
	CRC_Structure->Poly=Poly;
	CRC_Structure->IOTurn=IOTurn;
	CRC_Structure->Initial=Initial;
	CRC_Structure->OUTXOR=OUTXOR;
}

/*
 *函数简介:CRC计算
 *参数说明:CRC结构体
 *参数说明:8bits输入数据数组
 *参数说明:数组长度
 *参数说明:8bitsCRC校验值数组
 *返回类型:无
 *备注:CRC校验值拆解成8bits数组时,低位在前
 */
void CRC_Calc(CRC_CRCTypeDef *CRC_Structure,uint8_t *Data,uint8_t Length,uint8_t *CRC_Result)
{
	uint64_t Minuend=0;//被减数暂存值
	uint64_t CRC_Value=0;//CRC校验值
	
	/*===============初始数据 初始值异或 输入反转===============*/
	for(uint64_t i=0;i<(CRC_Structure->Width);i++)
	{
		uint8_t InitialThisByte=( (CRC_Structure->Initial) >> (((CRC_Structure->Width)-1-i)/8*8) ) & 0xFF;//当前初始值字节
		uint8_t DataThisByte=( Data[i/8] & (~InitialThisByte) ) | ( (~Data[i/8]) & InitialThisByte );//当前数据字节与初始值字节的异或结果
		Minuend<<=1;//按位移入
		Minuend|=( ( DataThisByte >> ( (2*(i%8)-7)*(CRC_Structure->IOTurn) + 7-i%8 ) ) & 0x01 );
	}
	Minuend<<=1;//移入第Width+1位
	Minuend|=( ( Data[(CRC_Structure->Width)/8] >> ( (2*((CRC_Structure->Width)%8)-7)*(CRC_Structure->IOTurn) + 7-(CRC_Structure->Width)%8 ) ) & 0x01 );
	
	/*===============CRC计算===============*/
	for(uint16_t i=(CRC_Structure->Width)+1;i<Length*8+(CRC_Structure->Width);i++)//异或相减加上移位,实现串行异或除法
	{
		if( Minuend >= ( (uint64_t)0x01 << (CRC_Structure->Width) ) )
			Minuend=( Minuend & (~(CRC_Structure->Poly)) ) | ( (~Minuend) & (CRC_Structure->Poly) );//异或相减
		Minuend<<=1;//移位移入下一位
		Minuend|=( ( Data[i/8] >> ( (2*(i%8)-7)*(CRC_Structure->IOTurn) + 7-i%8 ) ) & 0x01 );
	}
	if( Minuend >= ( (uint64_t)0x01 << (CRC_Structure->Width) ) )//处理最后一次异或减法
		Minuend=( Minuend & (~(CRC_Structure->Poly)) ) | ( (~Minuend) & (CRC_Structure->Poly) );//异或相减
	
	/*===============输出反转 输出结果异或===============*/
	if(CRC_Structure->IOTurn)//输出反转
		for(uint8_t i=0;i<(CRC_Structure->Width);i++)
		{
			CRC_Value<<=1;
			CRC_Value|=( (Minuend>>i) & 0x01 );//按位反转
		}
	else CRC_Value=Minuend;//输出不反转
	CRC_Value=( ( CRC_Value & (~(CRC_Structure->OUTXOR)) ) | ( (~CRC_Value) & (CRC_Structure->OUTXOR) ) );//结果异或运算
	
	for(uint8_t i=0;i<(CRC_Structure->Width)/4;i++)//将CRC校验值拆分成bits数组,且低位在前
		CRC_Result[i]=( CRC_Value >> (8*i) ) & 0xFF;
}
